
package org.linlinjava.litemall.wx.util;

import lombok.extern.log4j.Log4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;


public class Sign {
	//private final Log log = LogFactory.getLog(Sign.class);
	/*public static int sendRedPack(WeixinRedPacket sendRedPackPo, String keys, String wxCert)
			throws KeyStoreException, NoSuchAlgorithmException, IOException, KeyManagementException,
			UnrecoverableKeyException, DocumentException, CertificateException {

		// 把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("mch_billno", sendRedPackPo.getMch_billno());
		sParaTemp.put("mch_id", sendRedPackPo.getMch_id());
		sParaTemp.put("wxappid", sendRedPackPo.getWxappid());
		sParaTemp.put("send_name", sendRedPackPo.getSend_name());
		sParaTemp.put("re_openid", sendRedPackPo.getRe_openid());
		sParaTemp.put("total_amount", sendRedPackPo.getTotal_amount());
		sParaTemp.put("total_num", sendRedPackPo.getTotal_num());
		sParaTemp.put("wishing", sendRedPackPo.getWishing());
		sParaTemp.put("client_ip", sendRedPackPo.getClient_ip());
		sParaTemp.put("act_name", sendRedPackPo.getAct_name());
		sParaTemp.put("remark", sendRedPackPo.getRemark());
		sParaTemp.put("nonce_str", sendRedPackPo.getNonce_str());

		// 除去数组中的空值和签名参数
		Map<String, String> sPara = paraFilter(sParaTemp);
		String prestr = createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String key = "&key=" + keys; // 商户支付密钥
		String mysign = SendRedPackage.sign(prestr, key, "utf-8").toUpperCase();

		sendRedPackPo.setSign(mysign);
		log.info(sendRedPackPo);
		// 文本消息对象转换成xml
		String respXml = MessageUtil.messageToXml(sendRedPackPo);

		// 打印respXml发现，得到的xml中有“__”不对，应该替换成“_”
		respXml = respXml.replace("__", "_");
		log.info(respXml);
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();

		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		FileInputStream instream = new FileInputStream(new File(wxCert)); // 此处为证书所放的绝对路径
		try {
			keyStore.load(instream, sendRedPackPo.getMch_id().toCharArray());
		} finally {
			instream.close();
		}

		// Trust own CA and all self-signed certs
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, sendRedPackPo.getMch_id().toCharArray())
				.build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

		try {

			// 发红包接口地址
			HttpPost httpPost = new HttpPost(WechatConstants.SENDREDPACKURL);

			StringEntity reqEntity = new StringEntity(respXml, "utf-8");
		
			log.info(" 发红包状态："+respXml);
			// 设置类型
			reqEntity.setContentType("application/x-www-form-urlencoded");

			httpPost.setEntity(reqEntity);

			log.info("executing request" + httpPost.getRequestLine());

			CloseableHttpResponse response = httpclient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				log.info(response.getStatusLine());
				if (entity != null) {

					// 从request中取得输入流
					InputStream inputStream = entity.getContent();
					// 读取输入流
					SAXReader reader = new SAXReader();
					Document document = reader.read(inputStream);
					// 得到xml根元素
					Element root = document.getRootElement();
					// 得到根元素的所有子节点
					List<Element> elementList = root.elements();

					// 遍历所有子节点
					for (Element e : elementList)
						map.put(e.getName(), e.getText());

					// 释放资源
					inputStream.close();
					inputStream = null;

				}
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		log.info(map);
		// 返回状态码
		String return_code = map.get("return_code");
		if (StringUtils.isNotBlank(return_code)) {
			if (!"SUCCESS".equals(return_code)) {
				log.error("通信FAIL");
			} else {
				// 业务结果
				String result_code = map.get("result_code");
				if (StringUtils.isNotBlank(result_code)) {
					if ("SUCCESS".equals(return_code)) {
						log.info(map);
						return 1;
					}
				}
				// 错误代码
				String err_code = map.get("err_code");
				log.error(err_code);
				// 错误代码描述
				String err_code_des = map.get("err_code_des");
				log.error(err_code);
			}
		}
		// 返回信息
		String return_msg = map.get("return_msg");
		if (StringUtils.isNotBlank(return_msg)) {
			log.error(return_msg);
		}
		return 0;

	}*/

	public static String getLocalIpAddr() {

		String clientIP = null;
		Enumeration<NetworkInterface> networks = null;
		try {
			// 获取所有网卡设备
			networks = NetworkInterface.getNetworkInterfaces();
			if (networks == null) {
				// 没有网卡设备 打印日志 返回null结束
				//log.info("networks  is null");
				return null;
			}
		} catch (SocketException e) {
			//log.error(e.getMessage());
		}
		InetAddress ip;
		Enumeration<InetAddress> addrs;
		// 遍历网卡设备
		while (networks.hasMoreElements()) {
			NetworkInterface ni = networks.nextElement();
			try {
				// 过滤掉 loopback设备、虚拟网卡
				if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) {
					continue;
				}
			} catch (SocketException e) {
				//log.info(e.getMessage());
			}
			addrs = ni.getInetAddresses();
			if (addrs == null) {
				//log.info("InetAddress is null");
				continue;
			}
			// 遍历InetAddress信息
			while (addrs.hasMoreElements()) {
				ip = addrs.nextElement();
				if (!ip.isLoopbackAddress() && ip.isSiteLocalAddress() && ip.getHostAddress().indexOf(":") == -1) {
					try {
						clientIP = ip.toString().split("/")[1];
					} catch (ArrayIndexOutOfBoundsException e) {
						clientIP = null;
					}
				}
			}
		}
		//log.info("clientIP:" + clientIP);
		// System.out.println(clientIP);
		return clientIP;
	}

	/**
	 * 签名字符串
	 * 
	 * @param text          需要签名的字符串
	 * @param key           密钥
	 * @param input_charset 编码格式
	 * @return 签名结果
	 */
	public static String sign(String text, String key, String input_charset) {
		text = text + key;
		return DigestUtils.md5Hex(getContentBytes(text, input_charset));
	}

	/**
	 * 签名字符串
	 * 
	 * @param text          需要签名的字符串
	 * @param sign          签名结果
	 * @param key           密钥
	 * @param input_charset 编码格式
	 * @return 签名结果
	 */
	public static boolean verify(String text, String sign, String key, String input_charset) {
		text = text + key;
		String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
		if (mysign.equals(sign)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * @param content
	 * @param charset
	 * @return
	 * @throws SignatureException
	 * @throws UnsupportedEncodingException
	 */
	private static byte[] getContentBytes(String content, String charset) {
		if (charset == null || "".equals(charset)) {
			return content.getBytes();
		}
		try {
			return content.getBytes(charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
		}
	}

//   }

	/**
	 * 生成6位或10位随机数 param codeLength(多少位)
	 * 
	 * @return
	 */
	public static String createCode(int codeLength) {
		String code = "";
		for (int i = 0; i < codeLength; i++) {
			code += (int) (Math.random() * 9);
		}
		return code;
	}

	/*
	 * private static boolean isValidChar(char ch) { if ((ch >= '0' && ch <= '9') ||
	 * (ch >= 'A' && ch <= 'Z')|| (ch >= 'a' && ch <= 'z')) return true; if ((ch >=
	 * 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f)) return true;//
	 * 简体中文汉字编码 return false; }
	 */

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray 签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}

		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
					|| key.equalsIgnoreCase("sign_type")) {
				continue;
			}
			result.put(key, value);
		}

		return result;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params 需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	public static void main(String[] args) {
		getLocalIpAddr();
	}
}
